#include <iostream>
#include <fstream>
#include <memory>
#include <string>
#include <strings.h>
#include <cstring>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
#include "daemonize.hh"
using namespace std;

#define buffer_size 1024
// 设定 web根目录
#define web_root_path "./webroot"
// 设定 主页
#define home_page "homepage.html"
class tcp_server_t
{
public:
    tcp_server_t(string addr, uint16_t port)
    {
        // tcp
        _listen_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_socket_fd < 0)
        {
            cerr << "creat_listen_socket_error!";
        }
        // info
        sockaddr_in host_addr;
        bzero(&host_addr, sizeof(host_addr));
        host_addr.sin_addr.s_addr = (addr.empty() ? INADDR_ANY : inet_addr(addr.c_str()));
        host_addr.sin_family = AF_INET;
        host_addr.sin_port = htons(port);
        // bind
        if (bind(_listen_socket_fd, (const sockaddr *)&host_addr, sizeof(host_addr)) < 0)
        {
            cerr << "bind_error!";
        }
    }
    void run()
    {
        // 监听
        if (listen(_listen_socket_fd, 5) < 0)
        {
            cerr << "listen_error!";
        }
        sockaddr_in client;
        socklen_t client_len = sizeof(client);

        while (true)
        {
            // 连接
            int client_fd = accept(_listen_socket_fd, (sockaddr *)&client, &client_len);
            if (client_fd < 0)
            {
                cerr << "accept_error!";
            }
            // 新建执行流(子进程,或多线程)提供服务
            // 线程
            pthread_t tid = 0;
            client_thread_argc *argc = new client_thread_argc{client_fd, this};
            if (pthread_create(&tid, 0, thread_routine, argc) < 0)
            {
                cerr << "thread_create_error!";
            }
        }
    }

private:
    static void *thread_routine(void *argc_struct)
    {
        // 分离
        pthread_detach(pthread_self());
        auto argc = static_cast<client_thread_argc *>(argc_struct);
        char buffer[buffer_size];
        bzero(buffer, buffer_size);
        read(argc->_fd, buffer, buffer_size);
        // cout << buffer;
        string resorce(web_root_path);
        string buffer_str(buffer);
        string web_root_path_str(web_root_path);
        // 根据请求 确定真实路径
        resorce += argc->_this->get_path(buffer_str);
        // 读取资源
        string html_str = argc->_this->get_html(resorce);
        // 第一行 包括协议 版本 状态
        string response_str("HTTP/1.0 200 OK\r\n");
        // n行K-V属性 ("k:空格v")
        response_str += "Content-Type: text/html\r\n";
        response_str += "Content-Length: " + to_string(html_str.size()) + "\r\n";
        // 空行
        response_str += "\r\n";
        // 有效载荷
        response_str += html_str;
        // cout<<response_str;
        write(argc->_fd, response_str.c_str(), response_str.size());
        // 切记资源泄漏
        close(argc->_fd);
        delete argc;
    }
    string get_path(string &requst)
    {
        size_t pos_endl = requst.find("\r\n");
        if (pos_endl == 0)
            return "";
        string first_line = requst.substr(0, pos_endl);
        size_t pos_space_before = first_line.find(" ");
        if (pos_space_before == 0)
            return "";
        size_t pos_space_after = first_line.rfind(" ");
        if (pos_space_after == 0)
            return "";
        string path = first_line.substr(pos_space_before + 1, pos_space_after - (pos_space_before + 1));
        if (path.size() == 1 && path[0] == '/')
            path += home_page;
        return path;
    }
    string get_html(string &path)
    {
        ifstream ifs(path);
        if (!ifs.is_open())
            return "404";
        string content;
        string line;
        while (getline(ifs, line))
            content += line;
        ifs.close();
        return content;
    }

private:
    struct client_thread_argc
    {
        client_thread_argc(int fd, tcp_server_t *pthis)
            : _fd(fd), _this(pthis) { ; }
        tcp_server_t *_this;
        int _fd;
    };
    int _listen_socket_fd;
};